package com.wang.mall.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wang.mall.bean.*;
import com.wang.mall.constant.CartConstant;
import com.wang.mall.feign.ProductFeignService;
import com.wang.mall.feign.UserFeignService;
import com.wang.mall.mapper.OmsOrderMapper;
import com.wang.mall.model.R;
import com.wang.mall.service.OmsOrderItemService;
import com.wang.mall.service.OmsOrderService;
import com.wang.mall.service.ProductImageService;
import com.wang.mall.service.UmsMemberReceiveAddressService;
import com.wang.mall.to.SeckillSkuRedisTo;
import com.wang.mall.to.rabbitmq.SeckillOrderTo;
import com.wang.mall.vo.*;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class
OmsOrderServiceImpl extends ServiceImpl<OmsOrderMapper, OmsOrder> implements OmsOrderService {


    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    UserFeignService userFeignService;

    @Autowired
    OmsOrderItemService orderItemService;

    @Autowired
    private ProductFeignService productFeignService;


    @Autowired
    private RabbitTemplate rabbitTemplate;


    /**
     * 构建订单确认页数据
     *
     * @return
     */
    @Override
    public OrderConfirmVo generateOrder() {
        Long memberId = Long.valueOf(SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString());

        OrderConfirmVo orderConfirmVo = new OrderConfirmVo();

        // 查询会员信息的收货地址
        R<List<UmsMemberReceiveAddress>> r = userFeignService.getByMemberId(memberId);
        List<UmsMemberReceiveAddress> addressList = r.getData();
        orderConfirmVo.setAddressList(addressList); // 收货地址


        // 查询商品的订单项
        BoundHashOperations<String, Object, Object> cartOps = redisTemplate.boundHashOps(CartConstant.CART_PREFIX);
        String s = (String) cartOps.get(memberId.toString());
        CartRedisVo cartRedisVo = JSON.parseObject(s, CartRedisVo.class);
        List<CartItemVo> items = cartRedisVo.getItems();


        //设置商品是否有库存
        List<Long> productIds = items.stream().map(CartItemVo::getProductId).collect(Collectors.toList());
        R<List<ProductHasStockVo>> productsHasStockData = productFeignService.getProductsHasStock(productIds);
        List<ProductHasStockVo> data = productsHasStockData.getData();
        Map<Long, Boolean> hashStock = data.stream().collect(Collectors.toMap(ProductHasStockVo::getProductId, ProductHasStockVo::getHasStock));

        List<OrderItemVo> orderItems = new ArrayList<>();
        for (CartItemVo item : items) {
            if (item.getCheck()) { // 判断商品是否被选中
                OrderItemVo orderItemVo = new OrderItemVo();
                Boolean isHashStock = hashStock.get(item.getProductId());
                orderItemVo.setCount(item.getCount());
                orderItemVo.setImage(item.getImgUrl());
                orderItemVo.setPrice(item.getPrice());
                orderItemVo.setProductId(item.getProductId());
                orderItemVo.setTitle(item.getTitle());
                orderItemVo.setTotalPrice(item.getTotalPrice());
                orderItemVo.setHasStock(hashStock.get(item.getProductId()));
                orderItems.add(orderItemVo);
            }

        }

        orderConfirmVo.setItems(orderItems); // 订单商品项


        String token = UUID.randomUUID().toString().replace("-", "");
        orderConfirmVo.setOrderToken(token); // 订单token放置重复提交订单
        // 存储订单信息到redis中
        redisTemplate.opsForValue().set(CartConstant.USER_ORDER_PREFIX + memberId, token, 30, TimeUnit.MINUTES);

        return orderConfirmVo;
    }

    /**
     * 订单提交
     *
     * @param submitVo
     * @return
     */
    @Transactional
    @Override
    public SubmitOrderResponseVo submitOrder(OrderSubmitVo submitVo) {
        SubmitOrderResponseVo responseVo = new SubmitOrderResponseVo();


        Long memberId = Long.valueOf(SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString());

        // 1、验证令牌是否合法
        // 令牌的对比和删除必须保证原子性
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";

        String orderToken = submitVo.getOrderToken();
        // 原子验证令牌和删除令牌
        Long result = redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Collections.singletonList(CartConstant.USER_ORDER_PREFIX + memberId), orderToken);
        if (result == 0) {
            // 令牌验证失败
            responseVo.setCode(3);
            return responseVo;
        } else {
            // 令牌验证成功
            // 创建订单 ,
            OrderCreatedTo order = createOrder(submitVo);
            BigDecimal payPrice = order.getPayPrice();
            BigDecimal payPriceWeb = submitVo.getPayPrice();
            if (Math.abs(payPrice.subtract(payPriceWeb).doubleValue()) < 0.01) {
                // 页面的商品总价和数据库中的商品总价相差 小于0.01 , 就认为没问题
                //保存订单以及订单项数据
                saveOrder(order);

                // 锁定商品库存 , 只要有异常就回滚订单数据 TODO
                // 需要的数据 订单号 , 订单项 (productId, count,productName),
                WareProductLockVo lockVo = new WareProductLockVo();
                lockVo.setOrderSn(order.getOmsOrder().getOrderSn());
                List<OmsOrderItem> orderItemList = order.getOrderItemList();
                List<OrderItemVo> orderItemVos = orderItemList.stream().map(omsOrderItem -> {
                    OrderItemVo orderItemVo = new OrderItemVo();
                    orderItemVo.setProductId(omsOrderItem.getSkuId());
                    orderItemVo.setCount(omsOrderItem.getSkuQuantity());
                    orderItemVo.setTitle(omsOrderItem.getSkuName());
                    return orderItemVo;
                }).collect(Collectors.toList());
                lockVo.setLocks(orderItemVos);
                // 远程调用商品系统锁定库存
                // TODO 订单出现异常, 库存需要自动解锁, 使用消息队列
                R<List<LockStockResult>> r = productFeignService.orderLock(lockVo);
                List<LockStockResult> lockStockResults = r.getData();
                // 循环遍历判断所有的商品库存是否锁定成功
                boolean isLock = true;
                for (LockStockResult lockStockResult : lockStockResults) {
                    isLock = lockStockResult.getIsLock();
                }

                if (isLock) {
                    // 库存锁定成功

                    // 订单创建成功发送信息给rabbitMQ
                    rabbitTemplate.convertAndSend("wang-order-event-exchange", "order.create.order", order.getOmsOrder());

                    responseVo.setOmsOrder(order.getOmsOrder());
                    responseVo.setCode(0);
                    return responseVo;
                } else {
                    // 库存锁定失败
                    responseVo.setCode(1);
                    return responseVo;
                }

            } else { // 价格对比失败
                responseVo.setCode(2);
                return responseVo;
            }
        }
    }

    /**
     * 关闭订单
     *
     * @param omsOrder
     */
    @Override
    public void closeOrder(OmsOrder omsOrder) {
        // 查询当前订单的最新状态
        OmsOrder order = getById(omsOrder.getId());
        if (order != null && order.getStatus() == 0) {
            // 订单存在,并且订单的状态是待付款
            // 就进行关单
            OmsOrder updateOmsOrder = new OmsOrder();
            updateOmsOrder.setId(order.getId());
            updateOmsOrder.setStatus((byte) 4);
            updateById(updateOmsOrder);

            try {

                rabbitTemplate.convertAndSend("wang-order-event-exchange", "order.release.other", order);
            } catch (Exception e) {

            }
        }
    }

    /**
     * 获取支付订单的信息
     *
     * @param orderSn
     * @return
     */
    @Override
    public PayVo getOrderPay(String orderSn) {


        OmsOrder one = getOne(new LambdaQueryWrapper<OmsOrder>().eq(OmsOrder::getOrderSn, orderSn));
        PayVo payVo = new PayVo();
        payVo.setBody("品优购商城备注");
        payVo.setOut_trade_no(one.getOrderSn());
        String s = one.getPayAmount().setScale(2, BigDecimal.ROUND_UP).toString();
        payVo.setTotal_amount(s);
        return payVo;
    }


    @Autowired
    private PaymentInfoService paymentInfoService;

    /**
     * 处理支付结果
     *
     * @param payAsyncVo
     * @return
     */
    @Transactional
    @Override
    public String handlePayResult(PayAsyncVo payAsyncVo) {
        // 保存交易流水
        PaymentInfo paymentInfo = new PaymentInfo();
        paymentInfo.setAlipayTradeNo(payAsyncVo.getTrade_no());
        paymentInfo.setOrderSn(payAsyncVo.getOut_trade_no());
        paymentInfo.setPaymentStatus(payAsyncVo.getTrade_status());
        paymentInfo.setCallbackTime(payAsyncVo.getNotify_time());


        boolean save = paymentInfoService.save(paymentInfo);

        // 2、修改订单状态信息
        if (payAsyncVo.getTrade_status().equals("TRADE_SUCCESS") || payAsyncVo.getTrade_status().equals("TRADE_FINISHED")) {
            // 支付成功
            String orderSn = payAsyncVo.getOut_trade_no();
            // 修改订单状态为 已发货
            this.baseMapper.updateOrderStatus(orderSn, 1);

            // TODO 删除订单中购物车的信息, 如果秒杀的商品和购物车中的商品一致,就都会被删除掉,需要解决
            // 查询已经付款的订单的信息
            List<OmsOrderItem> orderItemList = orderItemService.list(new LambdaQueryWrapper<OmsOrderItem>().eq(OmsOrderItem::getOrderSn, orderSn));
            List<Long> productIds = orderItemList.stream().map(OmsOrderItem::getSkuId).collect(Collectors.toList());

            // 查询商品的订单项
            //  根据订单号查询用户的ID
            Long memberId = getOne(new LambdaQueryWrapper<OmsOrder>().eq(OmsOrder::getOrderSn, orderSn)).getMemberId();
            BoundHashOperations<String, Object, Object> cartOps = redisTemplate.boundHashOps(CartConstant.CART_PREFIX);
            String s = (String) cartOps.get(memberId.toString());
            CartRedisVo cartRedisVo = JSON.parseObject(s, CartRedisVo.class);
            List<CartItemVo> items = cartRedisVo.getItems();
            for (Long productId : productIds) {
                for (int i = 0; i < items.size(); i++) {
                    CartItemVo item = items.get(i);
                    if (productId.equals(item.getProductId())) {
                        // 如果购物车中的商品, 在订单支付的商品项中存在, 就删除
                        items.remove(item);
                    }
                }
            }


            cartRedisVo.setItems(items);
            cartRedisVo.setCountNum(0);
            cartRedisVo.setTotalAmount(new BigDecimal(0));
            // 将数据重新添加到redis
            String str = JSON.toJSONString(cartRedisVo);
            cartOps.put(memberId.toString(), str);
            return "success";
        }

        // 修改订单状态信息
        return "error";
    }

    /**
     * 获取当前用户待发货的订单
     *
     * @return
     */
    @Override
    public List<OmsOrder> getCurrentUserList() {
        Long memberId = Long.valueOf(SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString());
        List<OmsOrder> orderList = list(new LambdaQueryWrapper<OmsOrder>()
                .eq(OmsOrder::getMemberId, memberId).eq(OmsOrder::getStatus, 1).orderByDesc(OmsOrder::getCreateTime));
        if (!CollectionUtils.isEmpty(orderList)) {
            for (OmsOrder omsOrder : orderList) {
                List<OmsOrderItem> orderItemList = orderItemService.list(new LambdaQueryWrapper<OmsOrderItem>().eq(OmsOrderItem::getOrderSn, omsOrder.getOrderSn()));
                omsOrder.setOrderItemList(orderItemList);
            }
        }
        return orderList;
    }


    /**
     * 保存订单以及订单项数据
     *
     * @param order
     */
    private void saveOrder(OrderCreatedTo order) {
        OmsOrder omsOrder = order.getOmsOrder();
        omsOrder.setCreateTime(new Date());
        Long memberId = Long.valueOf(SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString());
        omsOrder.setMemberId(memberId);
        save(omsOrder);

        List<OmsOrderItem> orderItemList = order.getOrderItemList();
        orderItemService.saveBatch(orderItemList);

    }

    /**
     * 创建订单
     *
     * @param submitVo
     * @return
     */
    private OrderCreatedTo createOrder(OrderSubmitVo submitVo) {
        OrderCreatedTo orderCreatedTo = new OrderCreatedTo();


        OmsOrder omsOrder = new OmsOrder();

        // 1 生成订单号
        String orderSn = IdWorker.getTimeId();
        omsOrder.setOrderSn(orderSn);
        // 2 获取收货地址信息
        UmsMemberReceiveAddress address = userFeignService.getId(submitVo.getAddrId()).getData();
        omsOrder.setReceiverPhone(address.getPhone());
        omsOrder.setReceiverProvince(address.getProvince());
        omsOrder.setReceiverCity(address.getCity());
        omsOrder.setReceiverRegion(address.getRegion());
        omsOrder.setReceiverDetailAddress(address.getDetailAddress());
        omsOrder.setReceiverName(address.getName());
        omsOrder.setStatus((byte) 0);

        // 获取当前用户的订单项
        Long memberId = Long.valueOf(SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString());
        BoundHashOperations<String, Object, Object> cartOps = redisTemplate.boundHashOps(CartConstant.CART_PREFIX);
        String s = (String) cartOps.get(memberId.toString());
        CartRedisVo cartRedisVo = JSON.parseObject(s, CartRedisVo.class);
        List<CartItemVo> currentUserCartItems = cartRedisVo.getItems();
        List<OmsOrderItem> omsOrderItemList = new ArrayList<OmsOrderItem>();
        if (!CollectionUtils.isEmpty(currentUserCartItems)) {

            //还要检查商品是否有库存
            List<Long> collect = currentUserCartItems.stream().map(CartItemVo::getProductId).collect(Collectors.toList());
            R<List<ProductHasStockVo>> r = productFeignService.getProductsHasStock(collect);
            List<ProductHasStockVo> data = r.getData();
            Map<Long, Boolean> isStock = data.stream().collect(Collectors.toMap(ProductHasStockVo::getProductId, ProductHasStockVo::getHasStock));


            for (CartItemVo cartItemVo : currentUserCartItems) {

                if (cartItemVo.getCheck() && isStock.get(cartItemVo.getProductId())) { // 检查购物车中的商品是否被选中 ,
                    OmsOrderItem omsOrderItem = new OmsOrderItem();

                    omsOrderItem.setOrderSn(orderSn);
                    omsOrderItem.setSkuId(cartItemVo.getProductId());
                    omsOrderItem.setSkuName(cartItemVo.getTitle());
                    omsOrderItem.setSkuPrice(cartItemVo.getPrice());
                    omsOrderItem.setSkuPic(cartItemVo.getImgUrl());
                    omsOrderItem.setSkuQuantity(cartItemVo.getCount());

                    omsOrderItemList.add(omsOrderItem);
                }
            }

            orderCreatedTo.setOrderItemList(omsOrderItemList);
        }

        if (!CollectionUtils.isEmpty(omsOrderItemList)) {
            BigDecimal payPrice = new BigDecimal(0);
            for (OmsOrderItem omsOrderItem : omsOrderItemList) {
                payPrice = payPrice.add(omsOrderItem.getSkuPrice().multiply(new BigDecimal(omsOrderItem.getSkuQuantity())));
            }
            // 应该支付的金额
            orderCreatedTo.setPayPrice(payPrice);
            omsOrder.setPayAmount(payPrice);
        }


        orderCreatedTo.setOmsOrder(omsOrder);


        return orderCreatedTo;
    }

    @Autowired
    private UmsMemberReceiveAddressService umsMemberReceiveAddressService;


    @Autowired
    private ProductImageService productImageService;

    /**
     * 创建秒杀单
     *
     * @param seckillOrderTo
     */
    @Transactional
    @Override
    public void createdSeckillOrder(SeckillOrderTo seckillOrderTo) {


        // 保存订单信息
        OmsOrder omsOrder = new OmsOrder();
        omsOrder.setOrderSn(seckillOrderTo.getOrderSn());
        // 2 获取收货地址信息
        Long memberId = seckillOrderTo.getMemberId();

        List<UmsMemberReceiveAddress> receiveAddresses = umsMemberReceiveAddressService.list(new LambdaQueryWrapper<UmsMemberReceiveAddress>().eq(UmsMemberReceiveAddress::getMemberId, memberId));
        UmsMemberReceiveAddress address = receiveAddresses.get(0);

        omsOrder.setReceiverPhone(address.getPhone());
        omsOrder.setReceiverProvince(address.getProvince());
        omsOrder.setReceiverCity(address.getCity());
        omsOrder.setReceiverRegion(address.getRegion());
        omsOrder.setReceiverDetailAddress(address.getDetailAddress());
        omsOrder.setReceiverName(address.getName());
        omsOrder.setStatus((byte) 0);
        omsOrder.setMemberId(seckillOrderTo.getMemberId());
        omsOrder.setPayAmount(seckillOrderTo.getSeckillPrice().multiply(new BigDecimal(seckillOrderTo.getNum())));
        omsOrder.setCreateTime(new Date());


        // 构建订单项
        Long sessionId = seckillOrderTo.getPromotionSessionId();
        Long skuId = seckillOrderTo.getSkuId();

        OmsOrderItem omsOrderItem = new OmsOrderItem();
        omsOrderItem.setOrderSn(seckillOrderTo.getOrderSn());
        omsOrderItem.setSkuId(seckillOrderTo.getSkuId());
        omsOrderItem.setSkuPrice(seckillOrderTo.getSeckillPrice());
        omsOrderItem.setSkuQuantity(seckillOrderTo.getNum());


        BoundHashOperations<String, String, String> hashOperations = redisTemplate.boundHashOps("seckill:skus:");
        String s = hashOperations.get(sessionId + "_" + skuId);
        SeckillSkuRedisTo skuRedisTo = JSON.parseObject(s, SeckillSkuRedisTo.class);


        List<ProductImage> imageList = productImageService.list(new LambdaQueryWrapper<ProductImage>().eq(ProductImage::getProductId, skuId));

        omsOrderItem.setSkuPic(imageList.get(0).getImageUrl());
        omsOrderItem.setSkuName(skuRedisTo.getProduct().getName());


        // TODO 锁定库存
        WareProductLockVo lockVo = new WareProductLockVo();
        lockVo.setOrderSn(seckillOrderTo.getOrderSn());

        // 库存锁定项
        OrderItemVo orderItemVo = new OrderItemVo();
        orderItemVo.setProductId(omsOrderItem.getSkuId());
        orderItemVo.setCount(omsOrderItem.getSkuQuantity());
        orderItemVo.setTitle(omsOrderItem.getSkuName());
        lockVo.setLocks(Collections.singletonList(orderItemVo));


//        R<List<LockStockResult>> r = productFeignService.orderLock(lockVo);
//        List<LockStockResult> lockStockResults = r.getData();
//        // 循环遍历判断所有的商品库存是否锁定成功
//        boolean isLock = true;
//        for (LockStockResult lockStockResult : lockStockResults) {
//            isLock = lockStockResult.getIsLock();
//        }
//
//        if (isLock) {
//            // 库存锁定成功
//
//            // 订单创建成功发送信息给rabbitMQ
//            rabbitTemplate.convertAndSend("wang-order-event-exchange", "order.create.order", omsOrder);

            // 保存订单
            save(omsOrder);

            // 保存订单项
            orderItemService.save(omsOrderItem);
//        } else {
//            // 库存锁定失败
//
//        }


    }
}
